home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / flockXmlRpc.js < prev    next >
Text File  |  2007-10-18  |  13KB  |  384 lines

  1. // BEGIN FLOCK GPL
  2. //
  3. // Copyright Flock Inc. 2005-2007
  4. // http://flock.com
  5. //
  6. // This file may be used under the terms of of the
  7. // GNU General Public License Version 2 or later (the "GPL"),
  8. // http://www.gnu.org/licenses/gpl.html
  9. //
  10. // Software distributed under the License is distributed on an "AS IS" basis,
  11. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. // for the specific language governing rights and limitations under the
  13. // License.
  14. //
  15. // END FLOCK GPL
  16. //
  17.  
  18. const CC = Components.classes;
  19. const CI = Components.interfaces;
  20. const CR = Components.results;
  21. const CU = Components.utils;
  22.  
  23.  
  24. function DEBUG(X) { }
  25. //function DEBUG(X) { debug ('flockXmlRpc.js: '+X+'\n'); }
  26.  
  27. CU.import("resource:///modules/FlockXPCOMUtils.jsm");
  28. CU.import("resource:///modules/ISO8601DateUtils.jsm");
  29.  
  30. const FLOCK_XMLRPC_CLASS_NAME = "Flock XML-RPC";
  31. const FLOCK_XMLRPC_CLASS_ID =
  32.   Components.ID("{709f57f4-a4e4-41bb-a38d-86309fbc4858}");
  33. const FLOCK_XMLRPC_CONTRACT_ID = "@flock.com/xmlrpc/server;1";
  34.  
  35. const Base64 = {
  36.   chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
  37.   encode: function (aInput) {
  38.     var output = '';
  39.     while (aInput.length > 0) {
  40.       output += Base64.chars[aInput.charCodeAt(0) >> 2];
  41.       output += Base64.chars[((aInput.charCodeAt(0)&0x03) << 4) |
  42.         (aInput.length>1?((aInput.charCodeAt(1)&0xF0) >> 4):0)];
  43.       output += Base64.chars[aInput.length>1?
  44.         ((aInput.charCodeAt(1)&0x0F)<<2) |
  45.         (aInput.length>2?((aInput.charCodeAt(2)&0xC0) >> 6):0):64];
  46.       output += Base64.chars[aInput.length>2?
  47.         (aInput.charCodeAt(2)&0x3F):64];
  48.       if (aInput.length > 3) {
  49.         aInput = aInput.substr (3);
  50.       } else {
  51.         break;
  52.       }
  53.     }
  54.     return output;
  55.   },
  56.   decode: function (aInput) {
  57.     const regexp = new RegExp ('[^'+Base64.chars+']', 'g');
  58.     var output = '';
  59.  
  60.     aInput = aInput.replace (regexp, '');
  61.  
  62.     // FIXME: aInput MUST now be a multiple of four characters long
  63.  
  64.     function sixbits (i) {
  65.       if (i == '=') return 0;
  66.       return Base64.chars.indexOf (i);
  67.     }
  68.  
  69.     while (aInput.length >= 4) {
  70.       output += String.fromCharCode ((sixbits (aInput[0]) << 2) |
  71.         (sixbits (aInput[1]) >> 4));
  72.       if (aInput[2] == '=') {
  73.         break;
  74.       }
  75.       output += String.fromCharCode ((sixbits (aInput[1]) << 4) |
  76.         (sixbits (aInput[2]) >>2));
  77.       if (aInput[3] == '=') {
  78.         break;
  79.       }
  80.       output += String.fromCharCode (((sixbits (aInput[2]) << 6) & 0xC0) |
  81.         sixbits (aInput[3]));
  82.       aInput = aInput.substr (4);
  83.     }
  84.     return output;
  85.   }
  86. }
  87.  
  88.  
  89. var XmlRpcXml = {
  90.   build: function XRX_build(value) {
  91.     if (value == undefined) {
  92.       return null;
  93.     }
  94.  
  95.     // FIXME: do the next two blocks have the desired effect?
  96.     if (value.QueryInterface) {
  97.       value = value.QueryInterface(flockIXmlRpcValue);
  98.       if (value == null) {
  99.         return null;
  100.       }
  101.     } else {
  102.       return null;
  103.     }
  104.     try {
  105.       value = value.QueryInterface(flockIXmlRpcValue);
  106.     } catch (e) {
  107.       return value.toString();
  108.     }
  109.  
  110.     switch (value.XmlRpcType) {
  111.       case flockIXmlRpcValue.TYPE_INT:
  112.         return <int>{ String(value.IntValue) }</int>;
  113.       case flockIXmlRpcValue.TYPE_BOOLEAN:
  114.         return <boolean>{ value.BooleanValue ? 1 : 0 }</boolean>;
  115.       case flockIXmlRpcValue.TYPE_STRING:
  116.         return <string>{ value.StringValue }</string>;
  117.       case flockIXmlRpcValue.TYPE_DOUBLE:
  118.         return <double>{ String(value.DoubleValue) }</double>;
  119.       case flockIXmlRpcValue.TYPE_DATETIME:
  120.         var date = new Date();
  121.         date.setTime(value.DateTimeValue * 1000);
  122.         var datetime = ISO8601DateUtils.create(date);
  123.         return <dateTime.iso8601>{datetime}</dateTime.iso8601>;
  124.       case flockIXmlRpcValue.TYPE_ARRAY:
  125.         var elements = value.ArrayElements({});
  126.         var array = <array><data/></array>;
  127.         for (var i = 0; i < elements.length; i++) {
  128.           var q = XmlRpcXml.build(elements[i]);
  129.           if (q == null) {
  130.             continue;
  131.           }
  132.           array.data.foo = <value>{q}</value>;
  133.         }
  134.         return array;
  135.       case flockIXmlRpcValue.TYPE_STRUCT:
  136.         var keys = value.StructKeys({});
  137.         var struct = <struct/>;
  138.         for (var i in keys) {
  139.           var q = XmlRpcXml.build(value.StructItem(keys[i]));
  140.           if (q == null) {
  141.             continue;
  142.           }
  143.           struct.foo = <member>
  144.                          <name>{keys[i]}</name>
  145.                          <value>{q}</value>
  146.                        </member>;
  147.         }
  148.         return struct;
  149.       case flockIXmlRpcValue.TYPE_BASE64:
  150.         return <base64>{ Base64.encode(value.Base64Value) }</base64>;
  151.       default:
  152.         throw "error building XML";
  153.         return null;
  154.     }
  155.   },
  156.   parse: function XRX_parse(xml) {
  157.     DEBUG("XmlRpcXml.parse:" + xml);
  158.     if (xml == undefined) {
  159.       // this is the empty string
  160.       return "";
  161.     }
  162.     if (xml.nodeKind() == "text") {
  163.       // the default type in string
  164.       return XmlRpcValue.String(xml.toString());
  165.     }
  166.     switch (xml.name().toString()) {
  167.       case "int":
  168.       case "i4":
  169.         return XmlRpcValue.Int(parseInt(xml.text()));
  170.       case "boolean":
  171.         return XmlRpcValue.Boolean(parseInt(xml.text()) == 1);
  172.       case "string":
  173.         return XmlRpcValue.String (xml.text().toString());
  174.       case "double":
  175.         return XmlRpcValue.Double(parseFloat (xml.text()));
  176.       case "dateTime.iso8601":
  177.         var val = xml.text().toString();
  178.         var myDate = ISO8601DateUtils.parse(val);
  179.         return XmlRpcValue.DateTime(myDate);
  180.       case "array":
  181.         var arr = [];
  182.         for (var i = 0; i < xml.data.value.length(); i++) {
  183.           arr.push(XmlRpcXml.parse(xml.data.value[i].children()[0]));
  184.         }
  185.         return XmlRpcValue.Array(arr);
  186.       case "struct":
  187.         var struct = {};
  188.         for (var i = 0; i < xml.member.length(); i++) {
  189.           struct[xml.member[i].name.text()] =
  190.            XmlRpcXml.parse(xml.member[i].value.children()[0]);
  191.         }
  192.         return XmlRpcValue.Struct(struct);
  193.       case "base64":
  194.         return XmlRpcValue.Base64(Base64.decode(xml.text().toString()));
  195.       default:
  196.         throw "error parsing XML";
  197.     }
  198.   }
  199. }
  200.  
  201.  
  202.  
  203. // flockXmlRpcServer object
  204. function flockXmlRpcServerComponent() {
  205.   this.mURL = null;
  206.   this.mTimeout = null;
  207. }
  208.  
  209. flockXmlRpcServerComponent.prototype = new FlockXPCOMUtils.genericComponent(
  210.   FLOCK_XMLRPC_CLASS_NAME,
  211.   FLOCK_XMLRPC_CLASS_ID,
  212.   FLOCK_XMLRPC_CONTRACT_ID,
  213.   flockXmlRpcServerComponent,
  214.   0, // nsIClassInfo flags
  215.   [CI.flockIXmlRpcServer]
  216. );
  217.  
  218. flockXmlRpcServerComponent.prototype.init =
  219. function XRSC_init(aURL) {
  220.   DEBUG('flockXmlRpcServer.init("' + aURL + '")');
  221.   this.mURL = aURL;
  222.   this.mTimeout = 120 * 1000;
  223. }
  224.  
  225. flockXmlRpcServerComponent.prototype.call =
  226. function XRSC_call(aMethod, aArguments, aListener) {
  227.   // var aOptionalTimeoutInSeconds = 10;
  228.   DEBUG("flockXmlRpcServer.call("
  229.         + aMethod + ", "
  230.         + aArguments + ", "
  231.         + aListener + ")\n");
  232.  
  233.   if (aArguments.XmlRpcType != flockIXmlRpcValue.TYPE_ARRAY) {
  234.     aListener.onError("the arguments must be in an xmrpc array");
  235.     return;
  236.   }
  237.  
  238.   var methodCall = <methodCall/>;
  239.   methodCall.methodName = aMethod;
  240.  
  241.   var arguments = aArguments.ArrayElements({});
  242.   DEBUG("XMLRPC: got " + arguments.length + " arguments");
  243.   for (var i in arguments) {
  244.     DEBUG("XMLRPC: adding arg " + XmlRpcXml.build(arguments[i]));
  245.     methodCall.params.param +=
  246.       <param>
  247.         <value>{ XmlRpcXml.build(arguments[i]) }</value>
  248.       </param>;
  249.   }
  250.  
  251.   var url = this.mURL;
  252.   var timeout = this.mTimeout;
  253.   var callback = {};
  254.   callback.notify = function XRSC_call_callback_notify(timer) {
  255.     var xhr = CC["@mozilla.org/xmlextras/xmlhttprequest;1"]
  256.               .createInstance(CI.nsIXMLHttpRequest);
  257.     xhr.open("POST", url, true);
  258.     xhr.setRequestHeader("Content-Type", "text/xml");
  259.  
  260.     // FIXME: what about charsets?
  261.     // FIXME: should we make this configurable?
  262.     xhr.overrideMimeType("text/xml");
  263.  
  264.     xhr.onreadystatechange = function XRSC_call_xhr(aEvent) {
  265.       if (xhr.readyState == 4) {
  266.         if (!xhr.responseXML) {
  267.           aListener.onError (xhr.responseText);
  268.           return;
  269.         }
  270.  
  271.         if (xhr.status != 200) {
  272.           aListener.onError (xhr.statusText);
  273.           return;
  274.         }
  275.  
  276.         //save the state of the XML object directives
  277.         Orig_XML_ignoreComments = XML.ignoreComments;
  278.         Orig_XML_ignoreProcessingInstructions = XML.ignoreProcessingInstructions;
  279.         Orig_XML_ignoreWhitespace = XML.ignoreWhitespace;
  280.         Orig_XML_prettyPrinting = XML.prettyPrinting;
  281.         Orig_XML_prettyIndent = XML.prettyIndent;
  282.         //set them to what we need for the parser to behave
  283.         XML.ignoreComments  = true;
  284.         XML.ignoreProcessingInstructions  = true;
  285.         XML.ignoreWhitespace = true;
  286.         XML.prettyPrinting = false;
  287.         XML.prettyIndent = false;
  288.  
  289.         //var response = new XML(xhr.responseXML);
  290.         var serializer = CC["@mozilla.org/xmlextras/xmlserializer;1"]
  291.                          .createInstance(CI.nsIDOMSerializer);
  292.         var xmlStr =
  293.           serializer.serializeToString(xhr.responseXML.documentElement);
  294.  
  295.         var response = new XML(xmlStr);
  296.  
  297.         if (response.name() != "methodResponse" ||
  298.             !(response.params.param.value.length() == 1 ||
  299.             response.fault.value.struct.length() == 1))
  300.         {
  301.           aListener.onError("invalid response XML: " + xhr.responseText);
  302.           return;
  303.         }
  304.  
  305.         if (response.params.param.value.length() == 1) {
  306.           var resp = XmlRpcXml.parse(response.params.param.value.children()[0]);
  307.           aListener.onResult(resp);
  308.           //put them back like we found them before we return
  309.           XML.ignoreComments = Orig_XML_ignoreComments;
  310.           XML.ignoreProcessingInstructions = Orig_XML_ignoreProcessingInstructions;
  311.           XML.ignoreWhitespace = Orig_XML_ignoreWhitespace;
  312.           XML.prettyPrinting = Orig_XML_prettyPrinting;
  313.           XML.prettyIndent = Orig_XML_prettyIndent;
  314.           return;
  315.         }
  316.  
  317.         var fault =
  318.           XmlRpcValue.ToJavaScript(XmlRpcXml.parse(response.fault.value.struct));
  319.         if (fault["faultCode"] == undefined ||
  320.             fault["faultString"] == undefined)
  321.         {
  322.           aListener.onError("invalid response XML: " + xhr.responseText);
  323.           //put them back like we found them before we return
  324.           XML.ignoreComments = Orig_XML_ignoreComments;
  325.           XML.ignoreProcessingInstructions = Orig_XML_ignoreProcessingInstructions;
  326.           XML.ignoreWhitespace = Orig_XML_ignoreWhitespace;
  327.           XML.prettyPrinting = Orig_XML_prettyPrinting;
  328.           XML.prettyIndent = Orig_XML_prettyIndent;
  329.           return;
  330.         }
  331.  
  332.         aListener.onFault(fault["faultCode"], fault["faultString"]);
  333.         //put them back like we found them before we return
  334.         XML.ignoreComments = Orig_XML_ignoreComments;
  335.         XML.ignoreProcessingInstructions = Orig_XML_ignoreProcessingInstructions;
  336.         XML.ignoreWhitespace = Orig_XML_ignoreWhitespace;
  337.         XML.prettyPrinting = Orig_XML_prettyPrinting;
  338.         XML.prettyIndent = Orig_XML_prettyIndent;
  339.         return;
  340.       }
  341.     }
  342.  
  343.     DEBUG('XMLRPC: sending: '
  344.           + '<?xml version="1.0"?>\n'
  345.           + methodCall.toXMLString());
  346.     DEBUG('XMLRPC timeout is "' + timeout + '"');
  347.  
  348.     var timeoutCallback= {};
  349.     timeoutCallback.notify = function XRSC_call_timeout_notify(timer) {
  350.       DEBUG("timeoutCallback.notify called");
  351.       if (xhr == null) {
  352.         DEBUG("flockXmlRpcServerComponent.prototype.call.timeoutCallback "
  353.               + "called with null request!!");
  354.       } else if ((xhr != null) && (xhr.readyState != 4)) {
  355.         DEBUG("XMLRPC timed out");
  356.         //the request still exists and hasn't completed
  357.         delete xhr["onreadystatechange"];     //Kill the callback function
  358.         xhr.abort();                          //abort the request
  359.         aListener.onError("timeout");         //return an error to the caller
  360.       }
  361.     }
  362.  
  363.     var timeOutTimer = CC["@mozilla.org/timer;1"]
  364.                        .createInstance(CI.nsITimer);
  365.     timeOutTimer.initWithCallback(timeoutCallback, timeout,
  366.                                   CI.nsITimer.TYPE_ONE_SHOT);
  367.  
  368.     xhr.send('<?xml version="1.0"?>\n' + methodCall.toXMLString());
  369.   }
  370.  
  371.   var timer = CC["@mozilla.org/timer;1"].createInstance(CI.nsITimer);
  372.   timer.initWithCallback(callback, 1, CI.nsITimer.TYPE_ONE_SHOT);
  373. }
  374.  
  375.  
  376. // load the XMLRPC helper
  377. var loader = CC['@mozilla.org/moz/jssubscript-loader;1']
  378.              .getService(CI.mozIJSSubScriptLoader);
  379. loader.loadSubScript("chrome://flock/content/xmlrpc/xmlrpchelper.js");
  380.  
  381. var NSGetModule =
  382.   FlockXPCOMUtils.generateNSGetModule(FLOCK_XMLRPC_CLASS_NAME,
  383.                                       [flockXmlRpcServerComponent]);
  384.